package rmmk.algorithms.knn.math;

import rmmk.algorithms.preprocessing.config.DistanceMetric;

public class Distance {
	public static Double calculateDistance(Double[] a, Double[] b,
			DistanceMetric dm) {

		switch (dm) {
		case Euclides:
			return euclidean(a, b);
		case Manhattan:
			return manhattan(a, b);
		case Czybyszew:
			return czybyszew(a, b);
		}
		return null;
	}

	private static Double euclidean(Double[] a, Double[] b) {
		Double sum = 0.0d;

		for (int x = 0; x < a.length; ++x) {
			if (a[x] == 0.0) {
				if (b[x] == 1.0) {
					sum += b[x];
				} else if (b[x] != 0.0) {
					sum += Math.pow(b[x], 2);
				}
			} else if (a[x] == 1.0) {
				if (b[x] == 1.0)
					;
				else if (b[x] == 0.0) {
					sum += a[x];
				} else {
					sum += Math.pow(a[x] - b[x], 2);
				}
			} else {
				sum += Math.pow(a[x] - b[x], 2);
			}
		}

		return Math.sqrt(sum);
	}

	private static Double czybyszew(Double[] a, Double[] b) {
		Double max = 0.0;

		for (int i = 0; i < a.length; ++i) {
			Double dist = Math.abs(a[i] - b[i]);

			if (dist > max)
				max = dist;
		}

		return max;
	}

	private static Double manhattan(Double[] a, Double[] b) {
		Double sum = 0.0d;

		for (int x = 0; x < a.length; ++x)
			sum += Math.abs(a[x] - b[x]);

		return sum;
	}
}
